import numpy as np


class BankerAlgorithm:
    def __init__(self, available, max_need, allocation):
        self.available = np.array(available)
        self.max_need = np.array(max_need)
        self.allocation = np.array(allocation)
        self.need = self.max_need - self.allocation
        self.n_processes = len(max_need)  # 进程数
        self.n_resources = len(available)  # 资源类型数

    def is_safe(self):
        work = self.available.copy()
        finish = np.zeros(self.n_processes, dtype=bool)
        safe_sequence = []

        while True:
            found = False
            for i in range(self.n_processes):
                if not finish[i] and all(self.need[i] <= work):
                    # 找到可执行的进程
                    work += self.allocation[i]
                    finish[i] = True
                    safe_sequence.append(i)
                    found = True

            if not found:
                break

        if all(finish):
            print("系统安全，安全序列:", safe_sequence)
            return True
        else:
            print("系统不安全")
            return False

    def request_resources(self, process_id, request):
        request = np.array(request)

        # 步骤1：检查请求是否超过声明需求
        if not all(request <= self.need[process_id]):
            print("错误：请求超过进程最大需求")
            return False

        # 步骤2：检查是否有足够可用资源
        if not all(request <= self.available):
            print("警告：资源不足，进程需等待")
            return False

        # 步骤3：尝试分配
        self.available -= request
        self.allocation[process_id] += request
        self.need[process_id] -= request

        # 步骤4：检查安全性
        if self.is_safe():
            print("资源分配成功")
            return True
        else:
            # 撤销分配
            self.available += request
            self.allocation[process_id] -= request
            self.need[process_id] += request
            print("资源分配会导致系统不安全，已撤销")
            return False


# 使用示例
if __name__ == "__main__":
    # 示例数据
    available = [3, 3, 2]  # 可用资源
    max_need = [
        [7, 5, 3],  # P0
        [3, 2, 2],  # P1
        [9, 0, 2],  # P2
        [2, 2, 2],  # P3
        [4, 3, 3]  # P4
    ]
    allocation = [
        [0, 1, 0],  # P0
        [2, 0, 0],  # P1
        [3, 0, 2],  # P2
        [2, 1, 1],  # P3
        [0, 0, 2]  # P4
    ]

    banker = BankerAlgorithm(available, max_need, allocation)

    # 检查初始状态是否安全
    banker.is_safe()
